home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1994 November / macformat-018.iso / Comms Spectacular / mosaic / Helpers / Sparkle202 Folder.1 / Docs / Technical notes < prev   
Encoding:
Text File  |  1994-04-04  |  28.6 KB  |  579 lines  |  [TEXT/ALFA]

  1. Contents:
  2. ABOUT MPEG
  3. ABOUT CONVERSION TO QUICKTIME
  4. TIMING INFO
  5. ABOUT QT VM
  6. MISC SIZE AND TIMING NOTES
  7. ABOUT THE THREAD USAGE
  8. ABOUT THE RESOURCES.
  9.  
  10.  
  11. This file contains various pieces of informationa about MPEG and Sparkle. 
  12. Parts of it are notes I take for myself as I alter and test the program.
  13. I included them here because I thought some other mac programmers out there
  14. might be interested in such things. Read through what you care about and 
  15. understand and ignore the rest.
  16.  
  17.  
  18. -------------------------------------------------------------------------------
  19. ABOUT MPEG
  20.  
  21. MPEG is an international standard for video compression. It compresses 
  22. frames at two levels. Firstly frames are compressed internally, and 
  23. secondly frame differences are compressed rather than transmitting full 
  24. frames. 
  25. To understand MPEG one should first understand JPEG. MPEG uses the same 
  26. ideas as JPEG for much of its compression, and suffers from the same 
  27. limitations. 
  28. JPEG compression begins by changing an image's color space from RGB 
  29. planes to YUV planes, where Y is the luminance (brightness of the image) 
  30. and U and V store color information about the image. Half the color 
  31. resolution in the horizontal and vertical planes is dropped, because the 
  32. eye is less sensitive to color than to brightness. These YUV planes are 
  33. then divided into 8 by 8 blocks of pixels. The 64 coefficients in this 8 
  34. by 8 block are fourier transformed concentrating the energy of the image 
  35. in a few coefficients at low frequencies. The high frequency terms of the 
  36. fourier transform can be discarded as the eye is not sensitive to them. 
  37. The resultant fourier transform coefficients are then encoded using a 
  38. variable length coding scheme (basically Huffman coding) so that 
  39. frequently occuring patterns of coefficients are transmitted in few bits 
  40. and rare patterns transmitted in many bits.
  41.  
  42. MPEG goes beyond this by adding support for inter-frame compression. This 
  43. compression works by realizing that most video consists of foreground 
  44. objects moving over a largely static background. Thus rather than 
  45. transmit the foreground and background pictures over and over again, what 
  46. is transmitted is the motion of the foreground objects. Note that this is 
  47. different from the way QuickTime does interframe compression. What 
  48. QuickTime does is just to subtract the two images from each other and 
  49. compress the resultant image (which is hopefully largely blank space.)
  50. The MPEG scheme gives much better compression, but is much harder to 
  51. program. It is essentially a pattern recognition problem, looking at a 
  52. set of frames and deciding what pixels in the frame correspond to moving 
  53. objects---the sort of thing humans are very good at and computers very 
  54. bad at. For this reason, a complete MPEG compressor is complex and very 
  55. slow.
  56.  
  57. MPEG movies consist of three types of frames. I-frames are like JPEG 
  58. images and are compressed by themselves. P-frames are compressed based on 
  59. motion relative to a previous frame. B-frames are compressed based on 
  60. motion relative to both a previous frame AND a future frame. How do you 
  61. know what the future frame is? Well the MPEG data is not stored in the 
  62. same order as it is displayed. You have to decode future frames before 
  63. the B-frames on which they depend, then buffer the future frame 
  64. somewhere. This is why MPEG players need rather more memory than 
  65. QuickTime players.
  66.  
  67. As an example, here's a comment from my code.
  68. //About these three counters:
  69. //DecodedFrameNumber tells where we are in the file which we are currently
  70. //parsing, and is needed to find one's way around this file. It is incremented
  71. //every time a new frame is parsed.
  72. //DisplayedFrameNumber gives the number in temporal sequence of the frame that
  73. //is currently being shown on the screen. 
  74. //For I and P MPEGs these are the same,    but not for B MPEGs. For example a 
  75. //B MPEG may have the sequence:
  76. //    0    1    2    3    4    5    6    7    8    9    10    decodedFrameNumber
  77. //    I    P    B    B    I    B    B    P    B    B    I    frameType
  78. //    0     3    1    2 !    2    0    1    5    3    4 !    2    display number (within group)
  79. //     --------------|-----------------------|---- group boundaries
  80. //    1    4    2    3    7    5    6    10    8    9    ?    displayedFrameNumber
  81. //Note how the frames are clustered in groups, within which the Pict structure's
  82. //temporalReference field give the display number within that group. 
  83. //The displayedFrameNumber is basically a sum of these as one passes from group
  84. //to group, along with a condition of starting at one, rather than zero.
  85. //Now consider random access:
  86. //If we want to make a random access jump to a frame around displayed frame 5, 
  87. //we will be vectored to decodedFrameNumber 4, which will then be decoded, 
  88. //skipping past decodedFrameNumbers 5 and 6 (which depend on another frame in 
  89. //addition to decodedFrameNumber 4, and hence can't be displayed) to finally 
  90. //arrive at displaying decodedFrameNumber 4 as displayedFrameNumber 7. 
  91. //the variable decodedFrameNumberOfVisibleFrame keeps track of this fact that 
  92. //the displayedFrameNumber 7 actually represents decodedFrameNumber 4.
  93. //This information is necessary when stepping backwards through an MPEG. 
  94. //If we are at displayedFrameNumber 7 and step back, we will look back for I-frames
  95. //until we get to the I-frame at decodedFrameNumber==4. But this is the I-frame of
  96. //the image we are just displaying, so we actually need to then step back to an 
  97. //earlier I-frame. 
  98. //This complication is all necessary partially because of the way MPEG forward 
  99. //coding works, with the frame sequence on file not corresponding to the viewed
  100. //sequence, also partially because some B MPEGs do not have valid data for 
  101. //their Pict.temporalReference fields, thus one cannot rely on that field to be 
  102. //valid but one has to maintain a state machine as one parses through the file.
  103.  
  104. An MPEG movie can consist of only I-frames. This will be far from 
  105. optimally compressed, but is much easier to encode because the pattern 
  106. recognition is not needed. Such a movie is pretty much what you would get 
  107. if you made a QuickTime movie and used the JPEG codec as the compression 
  108. option. Because the I-frame movie is so much easier to calculate, it is 
  109. much more common. Sparkle checks if a movie uses only I-frames and if so 
  110. reduces its memory requirements since such movies do not need complex 
  111. buffering. In the PC world, many people talk about XING type MPEGs which 
  112. are pure I-frame MPEGs. These are produced by XING hardware on PCs and 
  113. played back using the XING MPEG player.
  114.  
  115. One problem with the MPEG standard is that many vendors seem to feel 
  116. which parts of it they support are optional. XING, for example, often 
  117. does not ends its MPEGs properly. It does not start frame numbering 
  118. properly, and does not correct frame numbering after MPEGs are edited.
  119. GC technologies produces MPEGs that have the frames essentially random 
  120. numbered, and has garbage frames at the start of its MPEGs.
  121. Wherever possible I have tried to adapt my code to common pathologies in 
  122. MPEG encoders. 
  123. I have also built in powerful yet computationally cheap 
  124. error-detection and recovery. For example a recent MPEG posted to usenet 
  125. drew widespread complaints because some of the uuencoded text was garbled 
  126. and the resultant MPEG crashed pretty much every decoder out there. But 
  127. Sparkle noticed the error and went on quite happily. Sparkle has also 
  128. proved quite robust in the face of MPEGs I have deliberately corrupted.
  129. If you come across any MPEG file that causes Sparkle to crash or produce 
  130. garbage, I WANT TO KNOW ABOUT IT. With a copy of the file, I can trace 
  131. through Sparkle, find just what causes the crash, and make Sparkle even 
  132. more robust.
  133.  
  134. For more details on MPEG, read the MPEG FAQ on USENET. It is posted once 
  135. a week to the picture groups and to news.answers.
  136.  
  137. ------------------------------------------------------------------------------
  138. ABOUT CONVERSION TO QUICKTIME
  139.  
  140. The following are notes I've made on conversion to QuickTime. I have  
  141. investigated this issue extensively, but not exhaustively. If someone has 
  142. comments on the subject---more extensive notes than I have, corrections, 
  143. whatever, please tell me.
  144.  
  145. All times I give are on my SE/30 with a 32-bit screen. People should 
  146. extrapolate to their machines---I guess LC IIs are about half as 
  147. fast and Centris/Quadras three to six times as fast.
  148.  
  149. The useful codecs are video, cinepak (used to be compact video) and jpeg. 
  150. JPEG compression at normal quality gives files of very good quality and not 
  151. much larger than pure I-frame MPEGs. A 120x160 image can play back at about 
  152. 4fps. Translated to an 040 and you get a useful frame rate. However JPEG 
  153. has a major problem in that when it decodes to a 32bit screen, it draws 
  154. directly to the screen, not to an offscreen Gworld unlike other codecs. 
  155. This produces movies with obvious tearing artifacts. When fast-dithering is 
  156. used to draw to other screen depths, it works fine. I don't understand why 
  157. this problem with 32 bit screens should be the case, but I have told Apple 
  158. about this problem and maybe it'll be fixed in a later release of 
  159. QuickTime. Meanwhile write to Apple and complain---they are holding back a 
  160. useful capability. 
  161.  
  162. With the video and cinepak compressors, it is very important to check the 
  163. key-frame rate checkbox. Key-frames are like MPEG I-frames. They are 
  164. compresed standalone and do not depend on other frames. The other frames 
  165. produced by the movie codecs depend on previous frames. Setting the 
  166. key-frame rate guarantees that at least that rate of key-frames (one 
  167. frame in used. for example) will be used. Checking the key-frame rate 
  168. checkbox allows the movie to use intra-frame compression (ie not just 
  169. key-frames) and gives movies half as small as they would otherwise be.
  170. The lower you set the key frame rate to (this means a larger number in 
  171. the QuickTime saving options dialog box) , the smaller you movie will be.
  172. For example a 72K MPEG (48 frames, 120x160, pure I-frame) became a 290K 
  173. movie without keyframes, a 160K movie with a key-frame rate of 1 in 8, 
  174. and a 138K movie with a key-frame rate of 1 in 96. 
  175. The price you pay for a low key-frame rate is that the movie has more 
  176. difficulty when playing backwards, or when randomly jumping around. I 
  177. don't find it a problem and usually use a key-frame rate of about 1 in 
  178. 100, but try for yourself to see what things are like.
  179. Video gives better quality results when a higher key-frame rate is used.
  180. Strangely cinepak appeared to give lower quality results (as well as a 
  181. larger movie) when more key-frame were used. 
  182. I'll have to investigate this further---I may have become confused when I 
  183. was making the measurements. Anyone want to confirm or deny this?
  184. (For comparison, this same movie became a 90K JPEG movie.)
  185.  
  186. I find video and cinepak give much the same file sizes at the same 
  187. (around normal) quality setting. The cinepak file is consistently a 
  188. little larger, but not enough to matter. The video file is consistently 
  189. lower quality for the same size as the cinepak file. However the video 
  190. low quality artifacts (blocks of solid color) I find less psychologically 
  191. irritating that the cinpeak low quality artifacts (general fuzzing of 
  192. borders like everything is drawn in crayon and watercolor). 
  193. However cinepak has the advantage of playing back much faster than video. 
  194. For a 120x160 image on my 32bit screen, I can get smooth playback with 
  195. cinepak at 24fps. Video can do smooth playback up to about 16 fps.
  196.  
  197. Fast dithering seems to be a good job for speed (at the cost of quality). 
  198. Unlike earlier versions of QuickTime, with 1.6.1 I found the same speed 
  199. of playback (ie same degree of skipping frames or not) at every screen 
  200. depth but 2 bit depth.
  201.  
  202. Cinepak can support a largish MPEG to QuickTime movie (352x240) at 6fps 
  203. on my mac, but no faster.
  204.  
  205. Compression using cinepak is SLOW SLOW SLOW. A 120x160 frame takes about 
  206. 10 seconds to compress. A 352x240 frame takes about a minute. In this 
  207. time your mac is stuck---it looks like it has crashed. Don't start saving 
  208. to cinepak QuickTime unless you are prepared to walk away from your mac 
  209. and not touch it until it's done.
  210. QuickTime 1.5 did not include anyway to do this compression in small 
  211. chunks so that it would run nicely in the background. I received word 
  212. today that QuickTime 1.6 does have this capability, so once I get the 
  213. relevant techincal documents and read them, I will add this ability.
  214.  
  215. See the WHY DOESN"T SPARKLE DO... section for more information about MPEG 
  216. frame rates and their relationship to QuickTime frame rates.
  217.  
  218. ------------------------------------------------------------------------------
  219.  
  220. WHY IS SPARKLE SO SLOW?
  221.  
  222. Largely because it's doing lots of work. 
  223.  
  224.  
  225. Here's a breakdown I made of timings on my old SE/30. 
  226. One thing to note is how diffuse the timings are. There is no obvious 
  227. bottleneck anywhere, no one thing whose increase will speed everything.
  228. Based on these numbers I did do a lot of tweaking, so they are not qute 
  229. accurate, but give order of magnitude.
  230. The YCrCb to RGB conversion is in assembler so can't really be sped up more.
  231. IDCT is in very convoluted C that I would hate to have to code in 
  232. assembler. Looking at the compiler output, I don't think I could do much 
  233. better. Parsing could be done rather better in assembler, but it is spread 
  234. over the entire code, across about five files, and is just to frightening 
  235. to contemplate converting to assembler.
  236. The really sad numbers are how much time WaitNextEvent and the MoviePlayer 
  237. chew up, but theirs no easy way around these. Maybe when I finally convert 
  238. this to a codec those numbers will go down.
  239.  
  240. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  241. Timings for Erika2.mpg:
  242.  
  243. Default: 
  244. playingSleepTime=6, progressUpdateInterval=10, 24bit screen, 5 frame buffer.
  245.     40 s
  246. As above, but 8 bit screen.
  247.     51 s
  248. As above but 8 bit grey screen.
  249.     40 s
  250.  
  251. As above, 24bit screen, with a 50 frame buffer:
  252.     38 s
  253. As above, but with a 2 frame buffer
  254.     37.5 s
  255.     
  256. Now 24bit screen, 50 frame buffer, progressUpdateInterval=180
  257.     38.4 s
  258. As above, progressUpdateInterval=1
  259.     40 s
  260.     
  261. Now 24bit screen, 50 frame buffer, progressUpdateInterval=10, playingSleepTime=0
  262.     35 s
  263. Now 24bit screen, 50 frame buffer, progressUpdateInterval=10, playingSleepTime=2
  264.     35 s
  265.     
  266. As above, 
  267. 24bit screen, 50 frame buffer, progressUpdateInterval=10, playingSleepTime=2
  268. but now in CMPEGDoc::Forward() loop until lastFrame.
  269. This means screen is updated, but WNE is never called.
  270.     30 s
  271. As above, but now no longer call CMPEGDoc::UpdateScreen()
  272.     28.5 s
  273. As above, but now no longer calls CControllerPane::SyncWithRedraw()
  274.     23 s
  275. As above, calling CMPEGDoc::UpdateScreen() but not CControllerPane::SyncWithRedraw()
  276.     24.7 s
  277.  
  278. As above, so no WNE, no calls to CMPEGDoc::UpdateScreen() or 
  279. CControllerPane::SyncWithRedraw(). Now in VidStream::UpdateFramesAfter() 
  280. we comment out YCrCbToRGB conversion.
  281.     16.3
  282. As above, if we use the non-assembly YCrCbToRGB
  283.     32 s
  284.  
  285. As above, so no WNE, no calls to CMPEGDoc::UpdateScreen() or 
  286. CControllerPane::SyncWithRedraw(), no YCrCbToRGB. Now in ParseBlocks, 
  287. in VidStream::ParseBlockIntra() we send all IDCTs through SparseIDCT().
  288.     11.3 s
  289. As above, but don't even call SparseIDCT()
  290.     8 s
  291. As above, changing VidStream::CompareBits() to pascal.
  292.     8 s
  293. I tried a bunch of low-level castings, changing the sizes of ints, etc,
  294. in the inner loop of parsing, DecodeDCTCoefficient() in Decoders.h, but 
  295. nothing helped much (maybe .1s in 8s, but with very ugly resulting code.)
  296. To establish the relative importance of the branches of this macro, I 
  297. collected counts for how often each was called over a run and arrived at:
  298.     General, non-ESCAPE case: 34966
  299.     General, ESCAPE case:     525
  300.     Special case, index==0:   1524
  301.     Special case, index==1:   1191
  302.     Special case, index==2:   451
  303.     Special case, index==3:   223
  304.  
  305. ================================================================================
  306. Conclusion:
  307.     Of the 40 s:
  308.     8         Parsing                                                 8
  309.     3.3        SparseIDCT/IDCT overhead                            11.3
  310.     5        IDCT                                                 16.3
  311.     6.7     YCrCbToRGB                                            23
  312.     1.5        CopyBits (at 24bits screen depth)                    24.5
  313.     5.5        MoviePlayer/ControllerPane (SyncWithRedraw())        30
  314.     3.5        WaitNextEvent                                        33.5
  315.     1.5     ProgressProc (if called every tick)                    35
  316.     
  317. By omitting cropping from YCrCbToRGB we can save about 2 s, but this 
  318. looks lousy on any image with a large region of black.
  319.  
  320. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  321.  
  322. ABOUT QT VM
  323.  
  324. Recently an INIT called QT VM has been released. This attempts to speed up 
  325. the behavior of QuickTime under virtual memory. What it does is that when 
  326. an application makes a NewGWorld call, asking that the GWorld be placed in 
  327. TempMem, the call fails. The idea is that it is faster to force the memory 
  328. manager to move memory around the app's partition, purging and 
  329. consolidating, than it is to allocate the GWorld in new memory which may 
  330. force paging to disk. For many situations this is true, but not for 
  331. Sparkle. Sparkle tries to make itself use smaller partitions by creating 
  332. GWorlds in TempMem. With the QT VM INIT enabled, it can't do that and has 
  333. to create the GWorlds in its partition. This means that the partition size 
  334. has to be made larger occasionally.
  335.  
  336. ================================================================================
  337.  
  338. MISC SIZE AND TIMING NOTES
  339.  
  340. These are rough notes I take as I alter the code, partially out of interest 
  341. and partially to guide me in where I need to change things.
  342. They may be of interest to some of you.
  343. They are now timed on my new Q610 and the SE/30 is in the hands of my 
  344. little brother.
  345. Like the SE/30 timings given above, they may not be be consistent with 
  346. each other as they reflect the state of the code at different times. In 
  347. between I may change the code quite a bit---mainly of interest are the 
  348. differences within any group of results.
  349.  
  350. Timings for Erika1.MPG under Sparkle 2.0 on my Q610.
  351. This is a 41 frame pure I 120x160 frame MPEG.
  352.  
  353. These times are for a version of the code that does not call WNE while playing:
  354.  
  355. 1) Effect of the screen depth/dithering on times: (non-optimized code)
  356.     24-bit color:      8.2 s
  357.     16-bit color     9.2 s
  358.      8-bit color      10.1 s
  359.      8-bit grey         8.6 s
  360.      Conclusion:
  361.          probably worth adding hints to speed up some parts of the code to compensate
  362.          for the dithering times:
  363.          1) For  8 bit color use 4x4 IDCT.
  364.          2) For  8 bit grey, omit YUV->RGB conversion.
  365.          3) For 16 bit color, use a special YUV->RGB conversion.
  366.          
  367. 2) Effect of various TC6 optmizations:     (24-bit screen)
  368.     Defer and combine stack adjusts:        7.8 s
  369.     Suppress redundant loads:                7.7 s
  370.     Automatic register assignment:            7.6 s
  371.     Global:    
  372.         Induction variables:                7.4 s
  373.         Common sub-expression elimination:    7.3 s
  374.         Code motion:                        7.2 s
  375.         Register coloring:                    6.6 s
  376.  
  377. 3) Effects of various displayings:    (no optimizations)
  378.     No progress proc at all (implies NOTHING ever updated on screen):    6.7 s
  379.     Progress proc called but does nothing:                                6.8 s
  380.     Progress proc updates movie controller/text track only:                7.6 s
  381.     Progress proc updates only MPEG frames, not movie controller        7.3 s
  382.     Progress proc updates both:                                            8.1 s
  383.     Conclusion:
  384.         of the 8.1 s, 0.8 s=10% is used updating movie controller and
  385.                       0.5 s= 6% is used updating the MPEG frames.
  386.  
  387. 4) Effect of the time allowed a thread before it yields:
  388.     Yield time=6000 ticks (ie never yield)        8.0 s
  389.                 180 ticks                         8.1 s
  390.                  60 ticks                        8.2 s
  391.                  20 ticks                        8.6 s
  392.     One would rather have a 20 tick time than a 60 tick time for increased 
  393.     user interactivity, but the time cost is rather stiff.
  394.     However by implementing a new thread scheduler, I should be able to reduce
  395.     this cost somewhat.
  396.  
  397. 5) Effect of yield time in the background:
  398.     We convert Erika1.MooV to an I-frame MPG.
  399.     FG time (yield time of 30 ticks): 1min 12s
  400.     BG time (yield time of 10 ticks)  2min 30s
  401.     BG time (yield time of 30 ticks)  2min 04s
  402.     Conclusion:
  403.         The longer yield time is obviously better but makes things more choppy.
  404.         Best is probably to implement a timer keeping track of how fast we are 
  405.         getting background NULLs and increasing bgYieldTicks as we notice less
  406.         fg activity.
  407.  
  408. 6) Note: 
  409.     I have tried to put yield brackets around all the hotpoints of the code to 
  410.     make it run well in background. The main problem for now, that I need to work 
  411.     around (ProgressProcs ?) is when the new frame is requested for coding an MPEG
  412.     or QT movie from a QT document. The fiddling that goes on to obtain this frame
  413.     can be fairly substantial, taking as long as 70 or 80 ticks for a simple 
  414.     160x120 movie. My guess is that QT doesn't do very smart caching about 
  415.     non-synch frames and has to decompress a long sequence to get to these frames.
  416.     Anyways, because of this we're stuck with a basic jerkiness at that 
  417.     granularity for now.
  418.  
  419. 7) Effects of four different P algorithms.
  420.     We convert Erika1.MooV to four MPEGs, all using a PPPI pattern,
  421.     with an I-quantization of 8 and a P-quantization of 10.
  422.     Algorithm:                Time:            Size:
  423.     Logarithmic                1:45 min        53 953
  424.     Two level                2:45 min        54 328
  425.     Subsample                3:45 min        54 765
  426.     Exhaustive                5:55 min        54 677
  427.     There was no obvious difference in quality between these MPEGs (and they 
  428.     were all pretty lousy). Thus there seems no real advantage to using anything
  429.     but the fastest algorithm.
  430.  
  431. 8) Effects of P-quantization.
  432.     Evene with a P-quantization of 8, the above setup does not produce as good 
  433.     an image as a pure I sequence (although the file size of 62K is much smaller.)
  434.     This appears to be largely due to the successive dependencies caused by 
  435.     the three successive P frames. 
  436.     Is it better to reduce the number of Ps or lower the P-quantization?
  437.     Using same pattern but P-quantization of 4 gives a file size of 98K and 
  438.     a quality lower than the pure I-frames (though certainly better than what 
  439.     we had). Using a pattern of PPI and P-quantization of 8 gives a file size of 
  440.     71K and the same sort of quality.
  441.     
  442.     Using a PBBIBB pattern and all quantizations as 8 gives a size of 60K and 
  443.     the same sort of quality. 
  444.     
  445.     Conclusions:
  446.     1) I need to use a higher quality source of images to investigate these 
  447.     affects. 
  448.     2) I think the P and B pattern matching criteria may be a bit dodgy, or maybe
  449.     some part of my code has problems with half-pixels or such.
  450.  
  451. 9) Effect of buffer size.
  452.     I played a 750K MPEG of 150 frames. With a buffer size of two frames, it took
  453.     36s. With a buffer size of 200 frames (ie entire movie) it took 33s. Thus
  454.     the larger buffer buys about 10% speed. 
  455.     So maybe, when time, create massive buffers which are in some way shrinkable.
  456. ----------------------------------------------------------------------------------
  457.  
  458. Sizings for Erika1.MPG under Sparkle 2.0
  459.  
  460. 1) Using only I-frame encoding with varying I-quantization:
  461.     I-quantization            size in bytes
  462.             1                    237 307
  463.             2                    179 960
  464.             4                    132 916
  465.             8                     92 210
  466.            16                     66 821
  467.            24                     42 658
  468.            32                      37 094
  469.            64                    25 955
  470.     DC terms only                 21 695
  471.     
  472.     Notes:
  473.     • These sizes are probably slightly larger than necessary as at present I do not
  474.       pad the excess pixels where frame size is smaller than the frame size in 
  475.       macroblocks, thus the DCT is encoding crud at those borders. By padding those 
  476.       to DC we'll get a small shrinkage in size.
  477.     • With this set of images (which were pretty lousy to begin with) a quantization 
  478.       level of 8 produced acceptable images, while a level of 16 produced 
  479.       unnacceptable quality.
  480.     • Once the quantization gets to 32 or higher, unexpected artifacts may occur in 
  481.       the form of blocks that are pure black or green, rather than what one would 
  482.       expect as pure DC terms. 
  483.       The reason for this is rounding error which rounds upwards. So for eaxmple 
  484.       the (1,0) DCT term may have a value of around 200, but when quantized, 
  485.       which produces an int from the division, the int may well be close to zero.
  486.       If it's less than .5, fine, but if it's just over .5, it goes to one and reverse
  487.       quantization gives us a value of 400 not 200, which is enough to completely muck
  488.       up the color balance of the block. 
  489.       Thus the useful range of quantizations is about 1---24, and use 1024 if you want
  490.       DC quantization.
  491. ================================================================================
  492.  
  493. ABOUT THE THREAD USAGE
  494.  
  495. I have nothing special to say about using threads except that I recommend 
  496. all serious Mac coders read the Apple documentation and use them. They 
  497. make life so much easier. The 1.x code was full of the most ghastly and 
  498. convoluted logic to enable breaking out of the MPEG decoder into the main 
  499. event loop and back again. However the 2.x code for encoding is ridiculously
  500. simple. We simply have the encoder, written (like a UNIX process or such) 
  501. as on long loop, then in the loop at appropriate points we make Yield() 
  502. calls.
  503.  
  504. The one thing that one has to be careful of is using exception handling in 
  505. the TCL. Because this is based on application wide globals, dreadful 
  506. things can happen in your thread when an exception occurs, a string of 
  507. CATCH handlers is followed up the stack, and at some point you leave the 
  508. stack of the thread and enter the "stack of the application". My solution 
  509. to this was to use custom thread context switchers which, on every context 
  510. switch, swap the appropriate exception handling globals.
  511. The custom context switchers also become a good place for updating the 
  512. timings of each thread and setting when it will next yield.
  513.  
  514. Another good idea is to encapsulate the thread in an object, then call 
  515. that object to yield instead of calling a Thread Manager yield directly. 
  516. The advantage of this is that the thread object can then see if the thread 
  517. manager is installed
  518. ---if so it yields,
  519. ---if not it can test for command-. and abort, or simly return control.
  520. This makes the code inside each inner loop (MPEG encoding or decoding or 
  521. QT encoding) much cleaner---simply yields with no tests for this or that 
  522. special situation.
  523.  
  524. At present I'm only using cooperative threads. It's not clear to me that 
  525. switching to pre-emptive threads is a useful excercise. One problem is, of 
  526. course, that pre-emptive threads make life rather trickier and coding more 
  527. complex. More to the point, pre-emptive threads only get half the CPU 
  528. time, while the WaitNextEvent() loop gets the other half. So by switching 
  529. to them I'd get lose half my speed, and not gain much. I might gain 
  530. slightly smoother user event support, especially in the background, but 
  531. that's not that bad right now and will improve when I install a custom 
  532. thread scheduler in place of the hokey quick kludge I'm using right now.
  533. If anyone out there has worked with pre-emptive threads and has opinions 
  534. on them one way or the other, please let me know.
  535.  
  536. A second major change in the 2.x code is I have now structured things 
  537. around a model of video source objects and video encoder objects, with any 
  538. video source able to be linked to any video encoder.
  539. This makes for very orthogonal extensible code.
  540. The natural extension of this is now to define more video sources. In 
  541. particular as soon as I can I hope to get to work on morphing routines, 
  542. with output that can be played to screen or saved in whatever video 
  543. formats I'm supporting by that stage. I have some ideas for morphing 
  544. algorithms, but if anyone can send me code, or tell me whence I can ftp it 
  545. (yes this usage of whence is correct) I'll obviously be able to get going 
  546. faster. Along the same lines, anyone know where I can get AVI source, or 
  547. the AVI specs so I can add AVI support?
  548. ================================================================================
  549.  
  550. ABOUT THE RESOURCES.
  551.  
  552. The default for the flags for all resources is purgable. 
  553. However there are some exceptions.
  554. • DLOGs and DITLs that will be opened by the TCL needed to be set nonpurgable
  555.     because of a bug in the TCL. I have altered CDLOGDialog to fix this and
  556.     these resources can now be purgable.
  557. • The DLOGs and DITLs used by CustomGetFile() and CustomPutFile() appear to 
  558.     need to be non-purgable even though IM says they can be purgable. If they 
  559.     are set    purgable the MemHell INIT registers errors during CustomGetFile() 
  560.     and CustomPutFile().
  561. • Menus may not be purgable because the menu manager does not allow that. 
  562.     Given this, one might as well make them preload and locked.
  563.     Likewise for the MBAR.
  564. • The DaTa resources, used to construct decoding tables, are mostly preload 
  565.     locked and treated just liked const global data. However there are a few 
  566.     small tables for which it is advantageous to load these into genuine global
  567.     arrays. For that case, the resources are marked purgable.
  568. • Marking resources Protected does not ever seem to be useful.
  569.  
  570. • If a dialog/alert makes uses of an ictb to change the font of text items, 
  571.     the associated dctb or actb must also be present or else nothing will 
  572.     happen.
  573. • Note that some of the dctb/itcb resources may appear redundant. However they 
  574.     prove to be necessary in unexpected ways. For example if they are not 
  575.     present for the CustomPutFile() DLOG, the dialog box drawn on screen will 
  576.     use dotted grey pattern to draw the items in the scrolling list of files,
  577.     rather than using a nice grey color. 
  578. ================================================================================
  579.